﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace TestSpyApi
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ScanProcesses();
        }

        private void btnReload_Click(object sender, EventArgs e)
        {
            ScanProcesses();
        }

        private void ScanProcesses()
        {
            tvControls.Nodes.Clear();

            foreach (Process procesInfo in Process.GetProcesses())
            {
                TreeNode tnProcess = new TreeNode(string.Format("process {0} {1:D}", procesInfo.ProcessName, procesInfo.Id));

                tvControls.Nodes.Add(tnProcess);

                foreach (ProcessThread threadInfo in procesInfo.Threads)
                {
                    IntPtr[] windows = GetWindowHandlesForThread(threadInfo.Id);

                    bool hasWnd = windows != null && windows.Length > 0;

                    TreeNode tnThread = new TreeNode(string.Format("thread {0:x}", threadInfo.Id));

                    tnProcess.Nodes.Add(tnThread);

                    if (hasWnd)
                    {

                        foreach (IntPtr hWnd in windows)
                        {
                            tnThread.Nodes.Add(hWnd.ToString(), string.Format("window {0:x} text:{1} caption:{2}", hWnd.ToInt32(), GetText(hWnd), GetEditText(hWnd)));
                        }
                    }
                }
            }
        }

        private IntPtr[] GetWindowHandlesForThread(int threadHandle)
        {
            _results.Clear();
            EnumWindows(WindowEnum, threadHandle);
            return _results.ToArray();
        }

        private delegate int EnumWindowsProc(IntPtr hwnd, int lParam);

        [DllImport("user32.Dll")]
        private static extern int EnumWindows(EnumWindowsProc x, int y);
        [DllImport("user32.dll")]
        public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);

        private List<IntPtr> _results = new List<IntPtr>();

        private int WindowEnum(IntPtr hWnd, int lParam)
        {
            int processID = 0;
            int threadID = GetWindowThreadProcessId(hWnd, out processID);
            if (threadID == lParam) _results.Add(hWnd);
            return 1;
        }

        // get window text

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetWindowTextLength(IntPtr hWnd);

        private static string GetText(IntPtr hWnd)
        {
            int length = GetWindowTextLength(hWnd);
            StringBuilder sb = new StringBuilder(length + 1);
            GetWindowText(hWnd, sb, sb.Capacity);
            return sb.ToString();
        }

        // get richedit text 

        public const int GWL_ID = -12;
        public const int WM_GETTEXT = 0x000D;

        [DllImport("User32.dll")]
        public static extern int GetWindowLong(IntPtr hWnd, int index);
        [DllImport("User32.dll")]
        public static extern IntPtr SendDlgItemMessage(IntPtr hWnd, int IDDlgItem, int uMsg, int nMaxCount, StringBuilder lpString);
        [DllImport("User32.dll")]
        public static extern IntPtr GetParent(IntPtr hWnd);

        private static StringBuilder GetEditText(IntPtr hWnd)
        {
            Int32 dwID = GetWindowLong(hWnd, GWL_ID);
            IntPtr hWndParent = GetParent(hWnd);
            StringBuilder title = new StringBuilder(128);
            SendDlgItemMessage(hWndParent, dwID, WM_GETTEXT, 128, title);
            return title;
        }

        // get control text

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);

        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        private void btnGetText_Click(object sender, EventArgs e)
        {
            if (txtTargetTitle.TextLength < 1) return;
            // Find the running app(e.g. notepad) window by title
            IntPtr Hwnd = FindWindow(null, txtTargetTitle.Text);
            lblWindowHandle.Text = string.Format("{0:x}", Hwnd.ToInt32());
            // Alloc memory for the buffer that recieves the text
            IntPtr Handle = Marshal.AllocHGlobal(100);
            // send WM_GWTTEXT message to the app(e.g. notepad) window
            int NumText = (int)SendMessage(Hwnd, WM_GETTEXT, (IntPtr)50, Handle);
            // copy the characters from the unmanaged memory to a managed string
            string Text = Marshal.PtrToStringUni(Handle);
            // Display the string using a label
            label1.Text = Text;
            // Find the control of the Running App by CLassName (e.g. Notepad Edit)
            IntPtr ChildHandle = FindWindowEx(Hwnd, IntPtr.Zero, txtClassName.Text, null);
            // Alloc memory for the buffer that recieves the text
            IntPtr Hndl = Marshal.AllocHGlobal(200);
            // Send The WM_GETTEXT Message
            NumText = (int)SendMessage(ChildHandle, WM_GETTEXT, (IntPtr)200, Hndl);
            // copy the characters from the unmanaged memory to a managed string
            Text = Marshal.PtrToStringUni(Hndl);
            // Display the string using a label
            label2.Text = Text;
        }

        private void btnGetText2_Click(object sender, EventArgs e)
        {
            if (txtWindowHandle.TextLength < 1) return;
            IntPtr Hwnd = new IntPtr(Convert.ToInt32(txtWindowHandle.Text, 16));
            // Alloc memory for the buffer that recieves the text
            IntPtr Handle = Marshal.AllocHGlobal(100);
            // send WM_GWTTEXT message to the app(e.g. notepad) window
            int NumText = (int)SendMessage(Hwnd, WM_GETTEXT, (IntPtr)50, Handle);
            lblWindowTitle.Text = Marshal.PtrToStringUni(Handle);

            if (txtChildClass.TextLength < 1) return;
            IntPtr ChildHandle = FindWindowEx(Hwnd, IntPtr.Zero, txtChildClass.Text, null);
            // Alloc memory for the buffer that recieves the text
            IntPtr Hndl = Marshal.AllocHGlobal(200);
            // Send The WM_GETTEXT Message
            NumText = (int)SendMessage(ChildHandle, WM_GETTEXT, (IntPtr)200, Hndl);
            // copy the characters from the unmanaged memory to a managed string
            string Text = Marshal.PtrToStringUni(Hndl);
            lblChildText.Text = Text;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            new Form2().Show();
        }
    }
}
